package fr.asip.cps3.exemple.modele.objets;

import iaik.pkcs.pkcs11.wrapper.CK_SLOT_INFO;
import iaik.pkcs.pkcs11.wrapper.PKCS11;
import iaik.pkcs.pkcs11.wrapper.PKCS11Constants;
import iaik.pkcs.pkcs11.wrapper.PKCS11Exception;

import org.apache.log4j.Logger;

import fr.asip.cps3.exemple.modele.exceptions.ExceptionObjet;
import fr.asip.cps3.exemple.modele.exceptions.ExceptionProgrammeExemple;
import fr.asip.cps3.exemple.modele.traitements.util.TraitementsUtil;

/**
 * Classe modélisant un slot
 *
 */
public class Slot {

	/**
	 * Le loggeur
	 */
	 private static Logger log = Logger.getLogger(Slot.class);
	
	/**
	 * Identifiant du slot
	 */
	long idSlot;
	
	/**
	 * Infos sur le slot
	 */
	private CK_SLOT_INFO info;
	
	/**
	 * Constructeur
	 * @param librairie Librairie PKCS#11 à utiliser
	 * @param idSlot Identifiant du slot
	 * @throws ExceptionObjet 
	 */
	public Slot(PKCS11 librairie,long idSlot) throws ExceptionObjet {

		this.idSlot = idSlot;
		
		chargeInfo(librairie);
		
	}

	/**
	 * (Re)chargement explicite des informations du slot
	 * @param librairie Librairie PKCS#11 à utiliser
	 * @throws ExceptionObjet 
	 */
	public void chargeInfo(PKCS11 librairie) throws ExceptionObjet {

		if(librairie != null) {
		
			try {
				info = librairie.C_GetSlotInfo(idSlot);
				
			} catch (PKCS11Exception e) {
				
				// Si une erreur PKCS#11 est rencontrée on log et on lève l'exception
				log.error("Une erreur est survenue lors de la recuperation des informations du slot : "+TraitementsUtil.retranscritCodeRetour(e.getErrorCode()));
				throw new ExceptionObjet(ExceptionProgrammeExemple.TYPE_OBJET_SLOT, "Une erreur est survenue lors de la récuperation des informations du slot");

			}
		
		} else {
			
			// Si la librairie est nulle il est impossible de récupérer les informations du slot
			log.error("La librairie est nulle");
			throw new ExceptionObjet(ExceptionProgrammeExemple.TYPE_OBJET_SLOT, "La librairie est nulle");
			
		}
		
	}
	
	/**
	 * Renvoie la description du slot
	 * @return Description du slot
	 * @throws ExceptionObjet 
	 */
	public String getDescription() throws ExceptionObjet {
		
		if(info != null)
			return new String(info.slotDescription);
		else {
			
			log.error("Les informations de la session sont nulles, la description du slot est indisponible");
			throw new ExceptionObjet(ExceptionProgrammeExemple.TYPE_OBJET_SLOT, "La description du slot est indisponible");
			
		}
	}

	/**
	 * Renvoie l'identifiant du fabricant du slot
	 * @return Identifiant du fabricant du slot
	 * @throws ExceptionObjet 
	 */
	public String getFabricant() throws ExceptionObjet {
		
		if(info != null)
			return new String(info.manufacturerID);
		else {
			
			log.error("Les informations de la session sont nulles, l'identifiant du fabricant du slot est indisponible");
			throw new ExceptionObjet(ExceptionProgrammeExemple.TYPE_OBJET_SLOT, "L'identifiant du fabricant du slot est indisponible");
			
		}
	}
	
	/**
	 * La carte est-elle présente?
	 * @return Réponse
	 * @throws ExceptionObjet 
	 */
	public boolean isCarte() throws ExceptionObjet {
		
		if(info != null)
			return (info.flags & PKCS11Constants.CKF_TOKEN_PRESENT)!=0?true:false;
		else {
			
			log.error("Les informations de la session sont nulles, l'information sur le slot est indisponible");
			throw new ExceptionObjet(ExceptionProgrammeExemple.TYPE_OBJET_SLOT, "L'information sur le slot est indisponible");
			
		}
	}
	
	/**
	 * Le lecteur gère-t-il les supports amovibles?
	 * @return Réponse
	 * @throws ExceptionObjet 
	 */
	public boolean isAmovible() throws ExceptionObjet {
		
		if(info != null)
			return (info.flags & PKCS11Constants.CKF_REMOVABLE_DEVICE)!=0?true:false;
		else {
			
			log.error("Les informations de la session sont nulles, l'information sur le slot est indisponible");
			throw new ExceptionObjet(ExceptionProgrammeExemple.TYPE_OBJET_SLOT, "L'information sur le slot est indisponible");
			
		}
		
	}
	
	/**
	 * Le slot est-il un slot matériel?
	 * @return Réponse
	 * @throws ExceptionObjet 
	 */
	public boolean isMateriel() throws ExceptionObjet {
		
		if(info != null)
			return (info.flags & PKCS11Constants.CKF_HW_SLOT)!=0?true:false;
		else {
			
			log.error("Les informations de la session sont nulles, l'information sur le slot est indisponible");
			throw new ExceptionObjet(ExceptionProgrammeExemple.TYPE_OBJET_SLOT, "L'information sur le slot est indisponible");
			
		}
		
	}
	

	/**
	 * Renvoie la version matérielle du slot
	 * @return Version matérielle du slot
	 * @throws ExceptionObjet 
	 */
	public String getVersionMaterielle() throws ExceptionObjet {
		
		if(info != null)
			return info.hardwareVersion.toString();
		else {
			
			log.error("Les informations de la session sont nulles, la version matérielle du slot est indisponible");
			throw new ExceptionObjet(ExceptionProgrammeExemple.TYPE_OBJET_SLOT, "La version matérielle du slot est indisponible");
			
		}
	}	

	/**
	 * Renvoie la version firmware du slot
	 * @return Version firmware du slot
	 * @throws ExceptionObjet 
	 */
	public String getVersionFirmware() throws ExceptionObjet {
		
		if(info != null)
			return info.firmwareVersion.toString();
		else {
			
			log.error("Les informations de la session sont nulles, la version firmware du slot est indisponible");
			throw new ExceptionObjet(ExceptionProgrammeExemple.TYPE_OBJET_SLOT, "La version firmware du slot est indisponible");
			
		}
	}
	
	/**
	 * Libellé du slot
	 * @return Libellé du slot
	 */
	public String getLibelle() {
		
		if(info != null)
			return "Slot "+Long.toString(idSlot)+" : "+(new String(info.slotDescription).trim());
		return "Slot "+Long.toString(idSlot);
		
	}

	/**
	 * Accesseur
	 * @return Identifiant du slot
	 */
	public long getIdSlot() {
		return idSlot;
	}

	@Override
	public String toString() {
		return getLibelle();
	}

}
